/*
    常用工具类：字符串分割器、uuid生成器、文件操作器、数据库操作器
*/
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <random>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <sys/stat.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include "sqlite3.h"
#include "logger.hpp"

namespace mq
{
    // 字符串操作类
    class StringHelper
    {
    public:
        // 分割字符串
        static int split(const std::string& str, const std::string& sep, std::vector<std::string>& res)
        {
            int begin = 0, end = 0;
            while((end = str.find(sep, begin)) != std::string::npos)
            {
                if(begin != end)
                    res.push_back(str.substr(begin, end - begin));
                begin = end + sep.size();
            }
            if(begin < str.size())
                res.push_back(str.substr(begin, str.size() - begin));
            return res.size();
        }
    };

    // uuid生成器
    class UUIDHelper
    {
    public:
        static std::string uuid()
        {
            // 思想：8个0~255的整数 + 8字节的字节序构成16字节的数据
            //       然后将其转换为16进制格式的字符串，就形成了32个16进制格式的字符串
            //       字符串采用8-4-4-4-12格式分割

            std::random_device rd; // 非确定性随机数生成器（机器随机数生成器）
            std::mt19937 gen(rd()); // 伪随机数生成器，梅森旋转算法
            std::uniform_int_distribution<int> distribution(0, 255);
            std::stringstream ss;
            for(int i = 0; i < 8; i++) // 生成8个0~255的整数，并转换为16进制格式字符串
            {
                ss << std::hex << std::setw(2) << std::setfill('0') << distribution(gen);
                if(i == 3 || i == 5 || i == 7) 
                    ss << "-";
            }
            static std::atomic<size_t> seq(0);
            size_t num = seq.fetch_add(1);
            for(int i = 7; i >= 0; i--)
            {
                ss << std::hex << std::setw(2) << std::setfill('0') << ((num >> (i * 8)) & 0xff);
                if(i == 6)
                    ss << "-";
            }
            return ss.str();
        }
    };

    // sqlite3数据库操作器: 一个对象对应一个数据库文件（数据库表）
    class Sqlite3Helper
    {
    public:
        /*
            对于查询结果的每一行都会调用一次这个回调函数
            data: 调用回调函数时传入的参数
            col_count: 一行数据的列数
            result: 一行数据的字符指针数组
            fields_name: 一行字段名的字符指针数组
        */
        // 执行sql时的回调函数类型
        typedef int(*SqlCallback)(void* data, int col_count, char** result, char** fields_name);

    public:
        Sqlite3Helper(const std::string& db_file) : _db_file(db_file)
        {
        }

        // 打开数据库文件
        bool open(int THREAD_SAFE_MODE = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_db_file.c_str(), &_db_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |  THREAD_SAFE_MODE, NULL);
            if(ret != SQLITE_OK)
            {
                ERR_LOG("open/create db failed: %s\n", sqlite3_errmsg(_db_handler));
                return false;
            }
            return true;
        }

        // 执行sql语句
        bool execute(const std::string& sql, SqlCallback callback, void* arg)
        {
            int ret = sqlite3_exec(_db_handler, sql.c_str(), callback, arg, NULL);
            if(ret != SQLITE_OK)
            {
                ERR_LOG("'%s' execute failed: %s\n", sql.c_str(), sqlite3_errmsg(_db_handler));
                return false;
            }
            return true;
        }

        // 关闭数据库文件
        void close()
        {
            if(_db_handler)
                sqlite3_close_v2(_db_handler);
        }

        ~Sqlite3Helper()
        {
            close();
        }

    private:
        sqlite3 *_db_handler;
        std::string _db_file;
    };

    // 文件操作器: 一个对象对应一个文件
    class FileHelper
    {
    public:
        FileHelper(const std::string& file): _file(file)
        {
        }

        // 判断文件是否存在
        bool exists()
        {
            struct stat st;
            return stat(_file.c_str(), &st) == 0;
        }

        // 获取文件大小
        size_t size()
        {
            struct stat st;
            int ret = stat(_file.c_str(), &st);
            if(ret != 0)
            {
                ERR_LOG("stat failed, %s file not exists\n", _file.c_str());
                return 0;
            }
            return st.st_size;
        }

        // 读文件
        bool read(char* buf, size_t offset, size_t size)
        {
            // 1. 打开文件
            std::ifstream ifs(_file, std::ios::binary | std::ios::in);
            if(!ifs.is_open())
            {
                ERR_LOG("open %s failed, %s\n", _file.c_str(), strerror(errno));
                return false;
            }

            // 2. 调整文件指针偏移量
            ifs.seekg(offset, std::ios::beg);
            if(ifs.fail()) {
                ERR_LOG("seek offset of %s to failed\n", _file.c_str());
                ifs.close();
                return false;
            }

            // 3. 读取数据
            ifs.read(buf, size);
            if(ifs.fail())
            {
                ERR_LOG("read failed from %s, %s\n", _file.c_str(), strerror(errno));
                ifs.close();
                return false;
            }

            // 4. 关闭文件
            ifs.close();
            return true;
        }

        // 写文件
        bool write(const char* buf, size_t offset, size_t size)
        {
            // 1. 打开文件
            std::fstream ofs(_file, std::ios::binary | std::ios::in | std::ios::out);
            if(!ofs.is_open())
            {
                ERR_LOG("open %s failed\n", _file.c_str());
                return false;
            }

            // 2. 调整文件指针偏移量
            ofs.seekp(offset, std::ios::beg);
            if(ofs.fail()) {
                ERR_LOG("seek offset of %s to failed\n", _file.c_str());
                ofs.close();
                return false;
            }

            // 3. 写入数据
            ofs.write(buf, size);
            if(ofs.fail())
            {
                ERR_LOG("write failed from %s\n", _file.c_str());
                ofs.close();
                return false;
            }

            // 4. 关闭文件
            ofs.close();
            return true;
        }

        // 截断文件到指定位置
        bool truncate(size_t size)
        {
            // if(::truncate(_file.c_str(), size))
            // {
            //     ERR_LOG("truncate %s to %ld failed\n", _file.c_str(), size);
            //     return false;
            // }
            // return true;
            std::string cmd = "truncate -s " + std::to_string(size) + " " + _file;
            return system(cmd.c_str()) == 0;
        }

        // 文件重命名
        bool rename(const std::string& new_file)
        {
            if(::rename(_file.c_str(), new_file.c_str()))
            {
                ERR_LOG("rename %s to %s failed\n", _file.c_str(), new_file.c_str());
                return false;
            }
            return true;
        }

        // 创建文件
        static bool createFile(const std::string& file)
        {
            std::ofstream ofs(file, std::ios::binary | std::ios::out);
            if(!ofs.is_open())
            {
                ERR_LOG("create %s failed\n", file.c_str());
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }

        // 删除文件
        static bool removeFile(const std::string& file)
        {
            return ::remove(file.c_str()) == 0;
        }


        // 创建目录
        static bool createDir(const std::string& file)
        {
            int pos = 0;
            while((pos = file.find("/", pos)) != std::string::npos)
            {
                std::string dir = file.substr(0, pos);
                int ret = mkdir(dir.c_str(), 0755);
                if(ret != 0 && errno != EEXIST)
                {
                    ERR_LOG("mkdir %s failed, %s\n", dir.c_str(), strerror(errno));
                    return false;
                }
                pos++;
            }
            int ret = mkdir(file.c_str(), 0755);
            if(ret != 0 && errno != EEXIST)
            {
                ERR_LOG("mkdir %s failed, %s\n", file.c_str(), strerror(errno));
                return false;
            }
            return true;
        }

        // 删除目录
        static bool removeDir(const std::string& file)
        {
            return system(("rm -rf " + file).c_str()) == 0;
        }

        // 获取父目录
        static std::string parentDir(const std::string& path)
        {
            int pos = path.find_last_of("/");
            if(pos == std::string::npos)
                return "./";
            return path.substr(0, pos);
        }

    private:
        const std::string _file;
    };
}